package com.xinyu.controller;


import com.xinyu.config.FileStorageProperties;
import com.xinyu.domain.Lesson;
import com.xinyu.service.ILessonService;
import com.xinyu.service.LessonDownloadTokenService;
import com.xinyu.utils.FileUploadUtil;
import com.xinyu.utils.JWTUtils;
import com.xinyu.vo.BaseResult;
import com.xinyu.vo.LessonDownloadToken;
import com.xinyu.vo.LessonRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author l
 * @since 2025-02-20
 */
@RestController
@RequestMapping("/lesson")
public class LessonController {

    private static final Logger AUDIT_LOGGER = LoggerFactory.getLogger("com.xinyu.audit.KnowledgeDownloadAudit");

    @Autowired
    private ILessonService lessonService;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private FileStorageProperties fileStorageProperties;

    @Autowired
    private LessonDownloadTokenService lessonDownloadTokenService;

    @Value("${file.upload.directory}")
    private String uploadDir;

    @GetMapping("{id}")
    public ResponseEntity<BaseResult> queryById(@PathVariable Integer id){
        Lesson lesson = lessonService.queryById(id);
        Integer requesterId = JWTUtils.getUserIdFromToken(request.getHeader("Authorization"));
        applyPermissionMetadata(lesson);
        return ResponseEntity.ok(BaseResult.ok(lesson));
    }

    @PostMapping("queryByCondition")
    public ResponseEntity<BaseResult> queryByCondition(@RequestBody LessonRequest lessonRequest){
        Integer requesterId = JWTUtils.getUserIdFromToken(request.getHeader("Authorization"));
        lessonRequest.setRequesterId(requesterId);
        BaseResult br = lessonService.queryByCondition(lessonRequest);
        return ResponseEntity.ok(br);
    }


    @PostMapping("/save")
    public ResponseEntity<BaseResult> saveDailyLogWithAttachment(@RequestBody Lesson lesson) {
        // 1 当前登录用户的id
        String token = request.getHeader("Authorization");
        lesson.setUserId(JWTUtils.getUserIdFromToken(token));

        //2 设置发布时间-当前系统时间
        LocalDateTime now = LocalDateTime.now();
        // 格式化时间（可选）
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = now.format(formatter);
        lesson.setPublishTime(formattedDateTime);
        normalizeAttachment(lesson);

        lessonService.save(lesson);
        return ResponseEntity.ok(BaseResult.ok());
    }


    @PostMapping("/update")
    public ResponseEntity<BaseResult> updateDailyLogWithAttachment(@RequestBody Lesson lesson) {
        normalizeAttachment(lesson);
        lessonService.updateById(lesson);
        return ResponseEntity.ok(BaseResult.ok());
    }

    @PostMapping("/{id}/download-token")
    public ResponseEntity<BaseResult> requestDownloadToken(@PathVariable Integer id) {
        Lesson lesson = lessonService.getById(id);
        if (lesson == null || StringUtils.isBlank(lesson.getAttachment())) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(BaseResult.error("未找到可下载的SOP"));
        }
        Integer requesterId = JWTUtils.getUserIdFromToken(request.getHeader("Authorization"));
        if (requesterId == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(BaseResult.error("未登录"));
        }

        String relativePath = stripBaseUrl(lesson.getAttachment());
        LessonDownloadToken token = lessonDownloadTokenService.issueToken(
                lesson.getId(),
                requesterId,
                relativePath,
                lesson.getAttachmentName());

        Map<String, Object> payload = new HashMap<>();
        payload.put("token", token.getToken());
        payload.put("expireAt", token.getExpireAt().toEpochMilli());
        payload.put("lessonId", lesson.getId());
        return ResponseEntity.ok(BaseResult.ok(payload));
    }

    @GetMapping("/download/{token}")
    public ResponseEntity<?> downloadLesson(@PathVariable String token) {
        LessonDownloadToken payload = lessonDownloadTokenService.consume(token);
        if (payload == null) {
            AUDIT_LOGGER.warn("EXPIRED|token={}", token);
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body("下载链接已失效");
        }
        try {
            Path filePath = resolveLessonFile(payload.getRelativePath());
            if (!Files.exists(filePath) || !Files.isReadable(filePath)) {
                AUDIT_LOGGER.warn("MISSING|token={} path={}", token, filePath);
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body("文件不存在或已被删除");
            }
            String fileName = StringUtils.defaultIfBlank(payload.getAttachmentName(), filePath.getFileName().toString());
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
            InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath));
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"")
                    .contentType(detectMediaType(filePath))
                    .body(resource);
        } catch (IOException e) {
            AUDIT_LOGGER.warn("ERROR|token={} msg={}", token, e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("下载失败，请稍后再试");
        }
    }

    private void applyPermissionMetadata(Lesson lesson) {
        if (lesson == null) {
            return;
        }
        lesson.setCanDownloadAttachment(Boolean.TRUE);
        lesson.setDownloadDenyReason(null);
    }

    private void normalizeAttachment(Lesson lesson) {
        if (lesson == null || StringUtils.isBlank(lesson.getAttachment())) {
            return;
        }
        lesson.setAttachment(stripBaseUrl(lesson.getAttachment()));
    }

    private String stripBaseUrl(String path) {
        if (StringUtils.isBlank(path)) {
            return path;
        }
        String prefix = fileStorageProperties.getBaseUrl();
        if (StringUtils.isNotBlank(prefix) && path.startsWith(prefix)) {
            return path.substring(prefix.length());
        }
        return path;
    }

    private Path resolveLessonFile(String relativePath) throws IOException {
        Path root = FileUploadUtil.resolveWritableRoot(uploadDir);
        String sanitized = StringUtils.defaultString(relativePath).replace("..", "");
        if (sanitized.startsWith("/")) {
            sanitized = sanitized.substring(1);
        }
        Path resolved = root.resolve(sanitized).normalize();
        if (!resolved.startsWith(root)) {
            throw new IOException("非法文件路径");
        }
        return resolved;
    }

    private MediaType detectMediaType(Path filePath) throws IOException {
        String probe = Files.probeContentType(filePath);
        return StringUtils.isBlank(probe) ? MediaType.APPLICATION_OCTET_STREAM : MediaType.parseMediaType(probe);
    }
}
